package com.bonc.ioc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bonc.ioc.dao.CollectionDao;
import com.bonc.ioc.dao.DataAssetDao;
import com.bonc.ioc.model.DataAssetInfo;
import com.bonc.ioc.service.IDataAssetService;
import com.bonc.ioc.util.JsonUtils;
import com.bonc.ioc.util.SizeConversionUtils;
import com.bonc.ioc.vo.DataAssetVo;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author ZhangXu
 * @date 2021/3/23 15:07
 */
@Service
public class DataAssetServiceImpl extends EsServiceImpl implements IDataAssetService {
    private static final Logger log = LoggerFactory.getLogger(DataAssetServiceImpl.class);

    @Resource
    private DataAssetDao dataAssetDao;

    @Resource
    private CollectionDao collectionDao;

    @Override
    public HashMap<String, Object> queryDataAsset(DataAssetVo param) {
        HashMap<String, Object> map = new HashMap<>();
        //拼接es搜索语句
        SearchSourceBuilder searchSourceBuilder = buildSearchSource(param);

        //创建并设置SearchRequest对象
        SearchRequest searchRequest = new SearchRequest();
        //设置request要搜索的索引和类型
        searchRequest.indices("data_assets");
        //设置SearchSourceBuilder查询属性
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, COMMON_OPTIONS);
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert searchResponse != null;
        SearchHits hits1 = searchResponse.getHits();
        System.out.println("-------" + hits1.getTotalHits());
        SearchHit[] hits = searchResponse.getHits().getHits();
        log.error("999999------" + hits.length);
        List<DataAssetInfo> dataAssetList = new LinkedList<>();
        Arrays.stream(hits).forEach(hit -> {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            //遍历高亮结果
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            log.info("数据资产 高亮显示结果 高亮部分={}", JSON.toJSONString(highlightFields));
            List<String> keyList = JsonUtils.getFirstLevelKeyList(JSON.toJSONString(highlightFields));
            log.info("数据资产 高亮显示结果 高亮部分keyList={}", keyList);
            for (String key : keyList) {
                HighlightField highlight = highlightFields.get(key);
                if (highlight != null) {
                    Text[] fragments = highlight.getFragments();
                    StringBuilder value = new StringBuilder();
                    for (Text text : fragments) {
                        value.append(text);
                    }
                    sourceAsMap.put(key, value.toString());
                }
            }
            log.info("数据资产 ES检索结果={}", sourceAsMap);
            DataAssetInfo dataAssetInfo = BeanUtil.mapToBean(sourceAsMap, DataAssetInfo.class, true);
            dataAssetInfo.setSize(SizeConversionUtils.getSize(dataAssetInfo.getSize()));
            //用户登录时，查询用户是否已经收藏该数据
            if (StringUtils.isNotBlank(param.getUserId())) {
                dataAssetInfo.setIsCollection(collectionDao.queryIsCollection(param.getUserId(), dataAssetInfo.getId()));
            }
            //更新数据库内使用量字段数据
            if (StringUtils.isNotBlank(dataAssetInfo.getUsedNum().toString())) {
                dataAssetDao.updateDataAssetUsedNum(dataAssetInfo.getId(), dataAssetInfo.getUsedNum());
            }
            dataAssetList.add(dataAssetInfo);
        });
        //进行数据分页
        int pageNum = 1;
        int pageSize = 10;
        if (param.getPageNum() != null) {
            pageNum = param.getPageNum();
        }
        if (param.getPageSize() != null) {
            pageSize = param.getPageSize();
        }
        List<DataAssetInfo> pageList = new LinkedList<>();
        int total = dataAssetList.size();
        pageList = dataAssetList.subList(pageSize * (pageNum - 1), (Math.min((pageSize * pageNum), total)));
        log.info("数据资产 检索分页结果={}", total);
        map.put("total", total);
        map.put("rows", pageList);
        return map;
    }

    @Override
    public DataAssetInfo queryDataDetail(Long id) {
        DataAssetInfo dataAssetInfo = dataAssetDao.selectDataDetailById(id);
        if (dataAssetInfo != null) {
            dataAssetInfo.setSize(SizeConversionUtils.getSize(dataAssetInfo.getSize()));
            dataAssetInfo.setCollections(collectionDao.queryCollections(dataAssetInfo.getId()));
        }
        dataAssetDao.updateDataAssetVisitNum(id);
        return dataAssetInfo;
    }

    /**
     * 拼接es搜索语句
     *
     * @param param
     * @return
     */
    private SearchSourceBuilder buildSearchSource(DataAssetVo param) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(10000);
        //定义query查询
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        //过滤失效数据：logstash每分钟同步数据库,通过同步时间筛选,过滤失效数据
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.add(Calendar.MINUTE, -3);
        Calendar afterTime = Calendar.getInstance();
        afterTime.add(Calendar.MINUTE, 3);

        // builder.must(QueryBuilders.rangeQuery("es_update_time").gte(sdf.format(beforeTime.getTime())).lte(sdf.format(afterTime.getTime())).format("yyyy-MM-dd HH:mm:ss"));
        //查询时间段
        if (StringUtils.isNotBlank(param.getStartTime()) && StringUtils.isNotBlank(param.getEndTime())) {
            builder.must(QueryBuilders.rangeQuery("release_time").gte(param.getStartTime()).lte(param.getEndTime()).format("yyyy-MM-dd HH:mm:ss"));
        }
        if (param.getSubjects() != null) {
            builder.must(QueryBuilders.matchQuery("subjects", param.getSubjects()));
        }
        if (param.getFormat() != null) {
            builder.must(QueryBuilders.matchQuery("data_format", param.getFormat()));
        }
        if (param.getScope() != null) {
            builder.must(QueryBuilders.matchQuery("use_scope", param.getScope()));
        }
        if (param.getDataOrigin() != null) {
            builder.must(QueryBuilders.matchQuery("data_origin", param.getDataOrigin()));
        }
        //分词检索
        if (StringUtils.isNotBlank(param.getText())) {
            builder.must(
                    QueryBuilders.boolQuery()
                            .should(QueryBuilders.matchQuery("title", param.getText()).boost(7.0f))
                            .should(QueryBuilders.matchQuery("sub_title", param.getText()).boost(6.0f))
                            .should(QueryBuilders.matchQuery("key_words", param.getText()).boost(5.0f))
                            .should(QueryBuilders.matchQuery("introduction", param.getText()).boost(4.0f))
                            .should(QueryBuilders.matchQuery("publisher_name", param.getText()).boost(3.0f))
                            .should(QueryBuilders.matchQuery("data_origin", param.getText()).boost(2.0f))
                            .should(QueryBuilders.matchQuery("content", param.getText()).boost(1.0f))
            );
        }
        log.info("ES检索命令 BoolQueryBuilder={}", builder.toString());
        searchSourceBuilder.query(builder);
        //定义高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置需要高亮的字段
        highlightBuilder.field("title").field("sub_title").field("key_words").field("introduction")
                .field("publisher_name").field("content")
                //多个高亮显示
                .requireFieldMatch(true)
                // 设置前缀、后缀
                .preTags("<font color='red'>").postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);
        //设置排序规则
        if (param.getSort() != null) {
            switch (param.getSort()) {
                case 1:
                    searchSourceBuilder.sort("release_time", SortOrder.DESC);
                    break;
                case 2:
                    searchSourceBuilder.sort("release_time", SortOrder.ASC);
                    break;
                case 3:
                    searchSourceBuilder.sort("visit_num", SortOrder.DESC);
                    break;
                case 4:
                    searchSourceBuilder.sort("visit_num", SortOrder.ASC);
                    break;
                case 5:
                    searchSourceBuilder.sort("used_num", SortOrder.DESC);
                    break;
                case 6:
                    searchSourceBuilder.sort("used_num", SortOrder.ASC);
                    break;
                default:
                    //  searchSourceBuilder.sort("release_time", SortOrder.DESC);
                    break;
            }
        } else {
            // searchSourceBuilder.sort("release_time", SortOrder.DESC);
        }
        log.info("ES检索命令 SearchSourceBuilder={}", searchSourceBuilder.toString());
        return searchSourceBuilder;
    }

    @Override
    public List<Map> getDataAssetListInfos() {
        return dataAssetDao.getDataAssetListInfos();
    }
}
